/****************************************************************************************
**  File: Lighting.hpp
**  Author: Asteroth
**  Date: 3-mag-2009
****************************************************************************************/

#ifndef __LIGHTING_HPP__
#define __LIGHTING_HPP__

class Lighting
{
	private:
		int lightCnt, maxLightCnt;
		bool* lights;
		float temp[4];

	public:
		Lighting() {
			lightCnt = 0;
			glGetIntegerv(GL_MAX_LIGHTS, &maxLightCnt);
			lights = new bool[maxLightCnt];
			for (int i=0; i<maxLightCnt; i++)
				lights[i] = false;
			glDisable(GL_LIGHT0);
			glDisable(GL_LIGHTING);
			glShadeModel(GL_SMOOTH);
		}

		~Lighting() {
			delete[] lights;
		}

		/// Enable lighting.
		inline void enable() {glEnable(GL_LIGHTING);}
		/// Enable a specific light.
		inline void enable(uint light) {glEnable(light);}
		/// Disable lighting.
		inline void disable() {glDisable(GL_LIGHTING);}
		/// Disable a specific light.
		inline void disable(uint light) {glDisable(light);}

		/// The max number of lights.
		inline int maxLightCount() {return maxLightCnt;}
		/// The number of lights created.
		inline int lightCount() {return lightCnt;}

		/// Creates a light and returns it's handle (0 on failure).
		inline uint create() {
			if (lightCnt<maxLightCnt)
			{
				for (int i=0; i<maxLightCnt; i++)
					if (lights[i]==false)
					{
						lights[i] = true;
						glEnable(GL_LIGHT0+i);
						return GL_LIGHT0+i;
					}
			}

			return 0;
		}

		/// Destroys a light.
		inline void destroy(uint light) {
			if (light>=GL_LIGHT0 && light<GL_LIGHT0+(uint)maxLightCnt)
			{
				glDisable(light);
				lights[light-GL_LIGHT0] = false;
			}
		}

		/// Set light settings.
		inline void setPosition(uint light, const core::Quaternion &pos) {
			temp[0] = pos.X;
			temp[1] = pos.Y;
			temp[2] = pos.Z;
			temp[3] = pos.W;
			glLightfv(light, GL_POSITION, temp);
		}

		inline void setDiffuse(uint light, const core::Quaternion &col) {
			temp[0] = col.X;
			temp[1] = col.Y;
			temp[2] = col.Z;
			temp[3] = col.W;
			glLightfv(light, GL_DIFFUSE, temp);
		}

		inline void setAmbient(uint light, const core::Quaternion &col) {
			temp[0] = col.X;
			temp[1] = col.Y;
			temp[2] = col.Z;
			temp[3] = col.W;
			glLightfv(light, GL_AMBIENT, temp);
		}

		inline void setSpecular(uint light, const core::Quaternion &col) {
			temp[0] = col.X;
			temp[1] = col.Y;
			temp[2] = col.Z;
			temp[3] = col.W;
			glLightfv(light, GL_SPECULAR, temp);
		}

		inline void setDirection(uint light, const core::Quaternion &dir) {
			temp[0] = dir.X;
			temp[1] = dir.Y;
			temp[2] = dir.Z;
			temp[3] = dir.W;
			glLightfv(light, GL_SPOT_DIRECTION, temp);
		}

		inline void setSpot(uint light, float cutoff = 180.0f, float exponent = 0.0f) {
			glLightf(light, GL_SPOT_CUTOFF, cutoff);
			glLightf(light, GL_SPOT_EXPONENT, exponent);
		}

		inline void setAttenuation(uint light, float constant = 1.0f, float linear = 0.0f, float quadric = 0.0f) {
			glLightf(light, GL_CONSTANT_ATTENUATION, constant);
			glLightf(light, GL_LINEAR_ATTENUATION, linear);
			glLightf(light, GL_QUADRATIC_ATTENUATION, quadric);
		}

		inline void setAmbientRadiation(const core::Quaternion &col) {
			temp[0] = col.X;
			temp[1] = col.Y;
			temp[2] = col.Z;
			temp[3] = col.W;
			glLightModelfv(GL_LIGHT_MODEL_AMBIENT, temp);
		}
};

#endif
